package cn.tedu.charging.account.service.geo.impl;

import cn.tedu.charging.account.pojo.entity.ChargingStation;
import cn.tedu.charging.account.service.geo.IRedisGeoCache;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.GeoOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * geo 服务接口实现
 *
 * @author wyy
 * @version 1.0
 */
@Slf4j
@Service
public class RedisGeoCacheImpl implements IRedisGeoCache {

    private final String GEO_KEY = "STATION";

    /** redis 客户端 */
    private final RedisTemplate redisTemplate;

    @Autowired
    public RedisGeoCacheImpl(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public Long saveChargingStationToRedis(Collection<ChargingStation> chargingStations) {
        log.info("开始把充电站信息保存到 Redis中: {}.", JSON.toJSONString(chargingStations));

        GeoOperations<String, Long> ops = redisTemplate.opsForGeo();

        Set<RedisGeoCommands.GeoLocation<Long>> locations = new HashSet<>();
//        chargingStations.forEach(item -> locations.add(new RedisGeoCommands.GeoLocation<String>(
//                item.getAddress(), new Point(item.getLongitude(), item.getLatitude())
//        )));

        for (ChargingStation item: chargingStations) {
            locations.add(new RedisGeoCommands.GeoLocation<Long>(
                item.getId(), new Point(item.getLongitude(), item.getLatitude())
            ));
        }

        log.info("储存充电站信息完成！");

        return ops.add(GEO_KEY, locations);
    }

    @Override
    public Long removeChargingStationToRedis(ChargingStation chargingStation){
        log.info("开始把充电站信息从 Redis 中移除: {}.", JSON.toJSONString(chargingStation));
        GeoOperations ops = redisTemplate.opsForGeo();
        return ops.remove(GEO_KEY, chargingStation.getId());
    }

    @Override
    public List<Point> getChargingStationPos(Long[] stationIds) {

        GeoOperations<String, Long> ops = redisTemplate.opsForGeo();

        return ops.position(GEO_KEY, stationIds);
    }

    @Override
    public Distance getTwoStationsDistance(Long stationId1, Long stationId2, Metric metric) {

        GeoOperations<String, Long> ops = redisTemplate.opsForGeo();

        return metric == null ? ops.distance(GEO_KEY, stationId1, stationId2) : ops.distance(GEO_KEY, stationId1, stationId2, metric);
    }

    @Override
    public GeoResults<RedisGeoCommands.GeoLocation<Long>> getPointRadius(Circle within, RedisGeoCommands.GeoRadiusCommandArgs args) {

        GeoOperations<String, Long> ops = redisTemplate.opsForGeo();

        return args == null ? ops.radius(GEO_KEY, within) : ops.radius(GEO_KEY, within, args);
    }

    @Override
    public GeoResults<RedisGeoCommands.GeoLocation<Long>> getMemberRadius(
            Long stationId, Distance distance, RedisGeoCommands.GeoRadiusCommandArgs args
    ) {

        GeoOperations<String, Long> ops = redisTemplate.opsForGeo();

        return args == null ? ops.radius(GEO_KEY, stationId, distance) : ops.radius(GEO_KEY, stationId, distance, args);
    }

    @Override
    public List<String> getStationGeoHash(Long[] stations) {

        GeoOperations<String, Long> ops = redisTemplate.opsForGeo();

        return ops.hash(GEO_KEY, stations);
    }
}
